package edu.mercer.sse554.bkp;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;

import com.google.common.base.Optional;
import com.google.common.base.Throwables;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * Properties loaded from ini file.<p>
 * 
 * Java Properties HashTable. Defaults loaded from ConfigurationConstants, 
 * 	overridden by any present in ini file.<p>
 * 
 * @see ConfigurationConstants
 */

public class Settings implements ConfigurationConstants 
{
	/** Properties */
	
	private static Optional<Properties> _prop = Optional.absent();
	
	
	/** 
	 * Settings no-arg constructor.<p> 
	 * 
	 * Used from static factory: access method.<p>
	 * 
	 * @see #access()
	 */
	
	private Settings()
	{
		super();

	}//constructor


	/**
	 * Initialize Settings.<p>
	 * 
	 * Ensure Path correct for ini file.<p>
	 * 
	 * @return  this
	 * 
	 * @throws IOException  error accessing ini file: not found, unreadable
	 */
	
	private synchronized Settings init() throws IOException
	{
		Properties propIn = new Properties();
		
		propIn.load( Files.newInputStream( Paths.get(SETTINGS_FILE) ) );
		
		_prop = Optional.of(propIn);
		
		return this;
		
	}//method
	

	/**
	 * Retrieve Properties.<p>
	 * 
	 * Static Properties collection used by application. R/W, loaded with
	 * 	values from ini file and defaults from ConfigurationConstants.<p>
	 * 
	 * @return  Properties populated with ini file values or defaults from 
	 * 	ConfigurationConstants
	 * 
	 * @see ConfigurationConstants
	 */
	
	static synchronized Properties access()
	{
		try
		{
			if( !_prop.isPresent() )
			{ 
				new Settings().init();

				/* load default values any properties ini file lacks */

				for(String codeConstant : attrs.keySet())
				{
					/* retrieve keys, defaults from multi-map in Config */
					
					String iniConstant = attrs.get(codeConstant)
							.toArray()[0]
							.toString();

					String iniDefault = attrs.get(codeConstant)
							.toArray()[1]
							.toString();

					checkNotNull(iniConstant, 
							"failure to find ini constant in Config: " + 
									codeConstant);

					checkNotNull(iniDefault, 
							"failure to find ini default in Config: " + 
									codeConstant);

					if( !_prop.get().containsKey(iniConstant) || 
						 _prop.get().getProperty(iniConstant) == null || 
						 _prop.get().getProperty(iniConstant).length() < 1 )
					{
						_prop.get().setProperty(iniConstant, iniDefault);

					}//if

					/* store properties by alternate keys for convenience */
					
					_prop.get().setProperty(codeConstant,
							
							_prop.get()
								 .getProperty(iniConstant) );
					
				}//for
				
			}//if initialization needed

		}
		catch(final IOException err)
		{
			/* 
			 * wrap IOException in RunTimeException to alleviate checked 
			 * Exception every time an application property is requested
			 * 
			 * preserve entire IOException, passing to custom Exception 
			 * constructor
			 */
			
			Throwables.propagate( new BackupSettingsException(
					"Error reading ini file", err) );
			
		}//try
			
		checkArgument( _prop.isPresent(), "failure initialize settings" );
		
		return _prop.get();
		
	}//method
	
	
}//class
